//
//  PYCHZInspectorController.m
//  PinyinContacts
//
//  Created by Xiaoping Zhang on 2/20/10.
//  Copyright 2010 Filters, Inc. All rights reserved.
//

#import "PYCHZInspectorController.h"
#import "PYCHzpy.h"

static NSString *kIndexColumnIdentifier = @"indexColumn";
static NSString *kHanziColumnIdentifier = @"hanziColumn";
static NSString *kPinyinColumnIdentifier = @"pinyinColumn";
static NSString *kPriorityColumnIdentifier = @"priorityColumn";

@interface PYCHZInspectorController ()

- (void) retrievingThreadMethod;
- (void)updateProgress:(id)object;
- (void)closeSheet;
- (void)cancelSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
- (void)searchTextChanged:(NSNotification *)note;
- (void)updateTableSelection:(NSNumber *)previousLastSelectedIndex;

@end

@implementation PYCHZInspectorController

@synthesize unfilteredContent, filteredContent, hzPYDBContext;

#pragma mark Initializer and dealloc

- (id) initWithObjectContext:(NSManagedObjectContext *)objectContext
{
	if (objectContext == nil)
		return nil;

	self = [super initWithWindowNibName:@"PYCHZInspector"];
	
	[self setHzPYDBContext:objectContext];
	
	isPopulated = NO;
	
	return self;
}

- (void)dealloc
{
	[super dealloc];
	
	[[NSNotificationCenter defaultCenter] removeObserver:self];
	// Possible bad access here
	[filteredContent release];
	[unfilteredContent release];
}

#pragma mark --
#pragma mark Overriden methods

- (void)awakeFromNib
{
	[progressView setHidden:NO];
	[searchView setHidden:YES];
	
	[[NSNotificationCenter defaultCenter] addObserver:self
											 selector:@selector(searchTextChanged:)
												 name:NSControlTextDidChangeNotification
											   object:searchField];
}

- (void)windowDidLoad
{
	retrievingThread = [[NSThread alloc] initWithTarget:self
											   selector:@selector(retrievingThreadMethod)
												 object:nil];
	[retrievingThread start];
}

- (void)windowWillClose:(NSNotification *)notification;
{
	[retrievingThread cancel];
}

#pragma mark --
#pragma mark Actions

- (IBAction) updateInpectingResult:(id)sender
{
	NSError *error;
	
	if (![hzPYDBContext save:&error])
	{
		NSLog(@"Error while saving: %@", [error localizedDescription]);
	}
	
	[self closeSheet];
}

- (IBAction) cancelInspecting:(id)sender
{
	if ([hzPYDBContext hasChanges])
	{
		NSAlert *alert = [[[NSAlert alloc] init] autorelease];
		
		[alert addButtonWithTitle:@"Yes"];
		[alert addButtonWithTitle:@"No"];
		[alert setMessageText:@"There are pending changes, are you sure to cancel?"];
		// [alert setInformativeText:@"Deleted records cannot be restored."];
		[alert setAlertStyle:NSWarningAlertStyle];
		
		[alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(cancelSheetDidEnd:returnCode:contextInfo:) contextInfo:nil];
	}
	else
	{
		[self closeSheet];
	}
}

- (IBAction) deleteItems:(id)sender
{
	NSIndexSet *selectedIndexes = [tableView selectedRowIndexes];
	if (selectedIndexes == nil || [selectedIndexes count] == 0)
	{
		return;
	}
	
	NSAlert *alert = [[[NSAlert alloc] init] autorelease];
	
	[alert addButtonWithTitle:@"Yes"];
	[alert addButtonWithTitle:@"No"];
	[alert setMessageText:@"Are you sure you want to delete these item(s)?"];
	[alert setInformativeText:@"Deleted item(s) cannot be restored."];
	[alert setAlertStyle:NSWarningAlertStyle];
	
	[alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(deleteSheetDidEnd:returnCode:contextInfo:) contextInfo:nil];
}

#pragma mark --
#pragma mark NSTableView DataSource

- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
	if (!isPopulated)
		return 0;
	else
		return [filteredContent count];
}

- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
	unichar buffer[4];
	
	id hzpy = [[self filteredContent] objectAtIndex:rowIndex];
	
	if (!hzpy)
		return nil;
	
	id columnIdentifier = [aTableColumn identifier];
	if (!columnIdentifier || ![columnIdentifier isKindOfClass:[NSString class]])
	{
		return nil;
	}
	
	if (!isPopulated)
		return nil;
	
	NSString *columnIdentifierString = (NSString *)columnIdentifier;
	id value = nil;
	
	if ([columnIdentifierString isEqualToString:kIndexColumnIdentifier])
	{
		value = [NSNumber numberWithInt:rowIndex + 1];
	}
	else if ([columnIdentifierString isEqualToString:kHanziColumnIdentifier])
	{
		if ([hzpy respondsToSelector:@selector(hanzi)])
		{
			value = [hzpy hanzi];
			[value getCharacters:buffer];
		}
	}
	else if ([columnIdentifierString isEqualToString:kPinyinColumnIdentifier])
	{
		if ([hzpy respondsToSelector:@selector(pinyin)])
		{
			value = [hzpy pinyin];
		}
	}
	else if ([columnIdentifierString isEqualToString:kPriorityColumnIdentifier])
	{
		if ([hzpy respondsToSelector:@selector(priority)])
		{
			value = [hzpy priority];
		}
	}
	
	return value;
}

- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
	if (!object)
		return;
	
	if (!isPopulated)
		return;
	
	PYCHzpy *hzpy = [filteredContent objectAtIndex:row];
	if (!hzpy)
		return;
	
	id columnIdentifier = [tableColumn identifier];
	if (!columnIdentifier || ![columnIdentifier isKindOfClass:[NSString class]])
	{
		return;
	}
	
	NSString *columnIdentifierString = (NSString *)columnIdentifier;
	
	if ([columnIdentifierString isEqualToString:kPriorityColumnIdentifier] &&
		[object isKindOfClass:[NSNumber class]])
	{
		// [hzpy setPriority:[NSNumber numberWithInt:[object intValue]]];
	}
	else if ([columnIdentifierString isEqualToString:kPinyinColumnIdentifier] &&
			 [object isKindOfClass:[NSString class]])
	{
		[hzpy setPinyin:object];
	}
	else if ([columnIdentifierString isEqualToString:kHanziColumnIdentifier] &&
			 [object isKindOfClass:[NSString class]])
	{
		[hzpy setHanzi:object];
	}
	
	return;
}

#pragma mark --
#pragma mark Data Retrieving

- (void) retrievingThreadMethod
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	
	[self performSelectorOnMainThread:@selector(updateProgress:) withObject:[NSNumber numberWithInt:0] waitUntilDone:YES];
	
	NSArray *allCharacters = [self retrieveAllCharacters];
	[self setUnfilteredContent:[NSMutableArray arrayWithArray:allCharacters]];
	[self setFilteredContent:[NSMutableArray arrayWithArray:allCharacters]];
	
	// Increase retain count in order to avoid filteredContent to be deallocated in dealloc method.
	[filteredContent retain];
	
	[self performSelectorOnMainThread:@selector(updateProgress:) withObject:[NSNumber numberWithInt:100] waitUntilDone:YES];
	
	[filteredContent release];
	[retrievingThread release];
	retrievingThread = nil;
	
	[pool release];
}

- (NSArray *)retrieveAllCharacters
{
	if (!hzPYDBContext)
		return nil;
	
	NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"hzpy" inManagedObjectContext:hzPYDBContext]; 
	NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; 
	[request setEntity:entityDescription];
	
	// Set example predicate and sort orderings... NSNumber *minimumSalary = ...; 
	NSPredicate *predicate = [NSPredicate predicateWithValue:YES];
	[request setPredicate:predicate];
	
	// Sort by priority
	NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"hanzi" ascending:YES];
	[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]]; [sortDescriptor release];
	
	NSError *error = nil; 
	NSArray *array = [hzPYDBContext executeFetchRequest:request error:&error]; 
	
	if (array == nil) 
	{
		// Deal with error...
	}
	
	return array;	
}

#pragma mark --
#pragma mark Sheet delegate methods

- (void)cancelSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
	if (NSAlertFirstButtonReturn == returnCode)
	{
		[hzPYDBContext rollback];
		[self closeSheet];
	}
}

- (void)deleteSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
	if (NSAlertFirstButtonReturn != returnCode)
	{
		return;
	}
	
	NSIndexSet *selectedIndexes = [tableView selectedRowIndexes];
	if (selectedIndexes == nil || [selectedIndexes count] == 0)
	{
		return;
	}
	
	NSUInteger currentIndex = [selectedIndexes firstIndex];
	NSMutableArray *itemsToDelete = [NSMutableArray array];
	
	while (currentIndex != NSNotFound)
	{
		id currentObject = [filteredContent objectAtIndex:currentIndex];
		[hzPYDBContext deleteObject:currentObject];
		currentIndex = [selectedIndexes indexGreaterThanIndex:currentIndex];
		
		[itemsToDelete addObject:currentObject];
	}
	
	NSError *error;
	
	if (![hzPYDBContext save:&error])
	{
		NSLog(@"Error while saving: %@", [error localizedDescription]);
		return;
	}
	
	[filteredContent removeObjectsAtIndexes:selectedIndexes];
	[unfilteredContent removeObjectsInArray:itemsToDelete];
	
	[tableView reloadData];

	[self performSelector:@selector(updateTableSelection:) withObject:[[NSNumber numberWithUnsignedInt:[selectedIndexes lastIndex]] retain] afterDelay:0];
}

#pragma mark --
#pragma mark Private methods

- (void)updateProgress:(id)object
{
	if (!object || ![object isKindOfClass:[NSNumber class]])
		return;
	
	[progressIndicator stopAnimation:self];
	
	if ([object intValue] < 100)
	{
		[progressIndicator startAnimation:self];
	}
	else if ([object intValue] == 100)
	{
		[progressView setHidden:YES];
		[searchView setHidden:NO];
		
		isPopulated = YES;
		
		[tableView reloadData];
		[tableView setNeedsDisplayInRect:[tableView visibleRect]];
	}
}

- (void)closeSheet
{
	[retrievingThread cancel];
	
	[[self window] orderOut:nil];
	[NSApp endSheet:[self window]];
}

- (void)searchTextChanged:(NSNotification *)note
{
	NSString *searchText = [searchField stringValue];
	
	if (searchText == nil || [searchText length] == 0)
	{
		[self setFilteredContent:[NSMutableArray arrayWithArray:unfilteredContent]];
	}
	else 
	{
		NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(hanzi = %@) OR (pinyin BEGINSWITH %@)", searchText, searchText];
	
		NSArray *resultArray = [unfilteredContent filteredArrayUsingPredicate:predicate];
		[self setFilteredContent:[NSMutableArray arrayWithArray:resultArray]];
	}

	[tableView reloadData];
}

- (void)updateTableSelection:(NSNumber *)previousLastSelectedIndex
{
	if (!previousLastSelectedIndex)
		return;
	
	NSUInteger itemCount = [filteredContent count];
	
	if (itemCount == 0)
		return;
	
	NSUInteger lastIndex = [previousLastSelectedIndex unsignedIntValue];
	[previousLastSelectedIndex release];
	
	if (lastIndex >= itemCount)
		lastIndex = itemCount - 1;
	
	[tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:lastIndex] byExtendingSelection:NO];
	[tableView scrollRowToVisible:lastIndex];
}

#pragma mark --

@end
